//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// Delete element of object.
//

# include "StdAfx.h"
# include "UndoRedo.h"
# include "Map.h"
# include "DeleteElement.h"
# include "RefreshHoles.h"
# include "Label.h"
# include "Selection.h"
# include "Globals.h"

class CDeleteElementAction : public CEditAction {
  public:
	CDeleteElementAction (rgn_t * _pRgn, size_t _cElementOrOrigin) :
		m_pRgn (_pRgn),
		m_cElementOrOrigin (_cElementOrOrigin),
		m_bWasModified ((_pRgn->dwFlags & rgn_t::fModified) != 0)
	{}

	virtual void GetName (string_t & _str) const;
	virtual cu_t CanUndo () const {return cuYes;}
	virtual bool Do ();
	virtual void Undo ();
	virtual void Redo ();

  private:
	rgn_t * const m_pRgn;
	size_t  const m_cElementOrOrigin;
	const bool    m_bWasModified;
};

void CDeleteElementAction::GetName (string_t & _str) const {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	_str.append ("delete element of [");
	GetHintText (* m_pRgn, _str);
	_str.append ("]");
}

bool CDeleteElementAction::Do () {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);

	bool bRgnIsEmpty = true;

	if (m_pRgn->Kind == rkPolygon || m_pRgn->Kind == rkPolyline) {
		rgn_elements_t & elements = m_pRgn->elements;
		const size_t cElements = elements.size ();

		assert (m_cElementOrOrigin < cElements);
		rgn_element_t & element = elements [m_cElementOrOrigin];
		element.bDeleted = true;
		element.ReleaseRGNodes ();

		for (size_t cElement = 0; cElement < cElements; ++ cElement)
			if (! elements [cElement].bDeleted) {
				bRgnIsEmpty = false;
				break;
			}
	} else {
		rgn_origins_t & origins = m_pRgn->origins;
		const size_t cOrigins = origins.size ();

		assert (m_cElementOrOrigin < cOrigins);
		origins [m_cElementOrOrigin].bDeleted = true;

		for (size_t cOrigin = 0; cOrigin < cOrigins; ++ cOrigin)
			if (! origins [cOrigin].bDeleted) {
				bRgnIsEmpty = false;
				break;
			}
	}

	m_pRgn->dwFlags |= rgn_t::fModified;

	// Remove whole object, if the element was the last one.
	if (bRgnIsEmpty)
		m_pRgn->Delete (g_map);

	return true;
}

void CDeleteElementAction::Undo () {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	if (m_pRgn->Kind == rkPolygon || m_pRgn->Kind == rkPolyline) {
		assert (m_cElementOrOrigin < m_pRgn->elements.size ());
		rgn_element_t & element = m_pRgn->elements [m_cElementOrOrigin];
		element.bDeleted = false;
		element.AddRefRGNodes ();
	} else {
		assert (m_cElementOrOrigin < m_pRgn->origins.size ());
		m_pRgn->origins [m_cElementOrOrigin].bDeleted = false;
	}

	if (! m_bWasModified)
		m_pRgn->dwFlags &= ~rgn_t::fModified;

	m_pRgn->Undelete (g_map);

	if (m_pRgn->HasRGNodes ())
		g_map.bDirtyRGNodes = true;
}

void CDeleteElementAction::Redo () {
	CDeleteElementAction::Do ();
}

///////////////////////////////////

void DeleteElement (rgn_t * _pRgn, size_t _cElementOrOrigin) {
	PerformEditAction (new CDeleteElementAction (_pRgn, _cElementOrOrigin));

	if (! _pRgn->IsDeleted () && _pRgn->IsPolygon ())
		RefreshHoles (_pRgn, true);
}
